﻿/*  战国传承3整合脚本(UTF-8 with BOM),功能是连发拳,连发武器,一键空中连击,一键忍术,一键大必杀,一键重踢+下下斩忍术,
  另加入numpad1切换静音,numpad0是暂停或老板键
  按键设定在全局变量那里,各种操作延时,以及我优化后的参数都在全局变量和注释.
  在Gui修改参数的话,必须要Submit_才能生效.按键调用了我自己制作的Key相关函数,都是些常用功能,顺便测试了外部文件调用与函数引用.
  脚本测试后觉得效果不错.
  
  By setycyas, 2022-11-03
*/

/* 全局设定 
*/ { ;不缩进块
#NoEnv
#Warn
SendMode Input
SetWorkingDir %A_ScriptDir%
} ;不缩进块

/* 调用自制的按键相关函数 
*/ { ;不缩进块
#Include ..\MyAhkModules\MyKey.ahk ;按键相关库,所有函数导出到MyKey对象中
} ;不缩进块

/* 常量,CT = const,部分常量因为使用的地方无法引用对象,只能用以CT开头的变量重复代替
*/ { ;不缩进块
CT := object()
CT.punchKey := "c", ;拳按键
CT.weaponKey := "x", ;武器按键
CT.macro12 := "t" ;12键一起按的宏 
CT.punchDuration := 30 ;100 ;按住拳键的持续时间
CT.weaponDuration := 30 ;150 ;按住武器键的持续时间
CT.punchDelay := 30 ;50 ;拳的连发延时,定义为上一次松开键到下一次按键的时间

;以下是用CT开头重复制作的常量,用于无法引用对象的地方
CTmacro12 := CT.macro12
CTpunchKey := CT.punchKey
CTweaponKey := CT.weaponKey
} ;不缩进块

/* 一般全局变量,GV = global Variables,在接收gui输入后重新设定,见函数makeData()
*/ { ;不缩进块
GV := object()
GV.jumpAtType := 1 ;空中连击开始类型,0为飞踢,1为武器
GV.weaponDelayArr := [] ;武器连发延时数组,由于要直接使用,记录的是上次松开键到下次按下键的时间
GV.jumpAtDelayArr := [] ;空中连击延时数组,由于要直接使用,记录的是上次松开键到下次按下键的时间
} ;不缩进块

/* 接收Gui输入的全局变量,以G=gui 开头,无法打包到object中
*/ { ;不缩进块
;游戏平台选择
Gtitle := ""
  
;武器的连发延时设定,这里的延时定义为从上次按下键到下一次按下键.
;测试结果:红,金鹰,影连370,400,310;白鬼,阿国-370,400,330;金刚-370,400,340
GweaponDelays := "370,400,310" 

;空中连击参数组,第一个数字为0或1,表示空中连击是以飞踢开始还是武器开始,0为飞踢,1为武器
;后面的几个数字是连击延时,这里延时定义为从上次按下键到下一次按下键,数字的个数决定连击次数,连击次数比数字个数多1
;测试后发现稳健的方法是:
;红:1;300,300,300(此参数其他人也还行) 影连,白鬼:1;350,350 金鹰,阿国:0;250,300,250
;再测试发现第一剑可以慢一点设定为350,后面的可以快一点,这样更多人能打出快连击,如白鬼350,250,300
GjumpAtParams := "1;350,250,300" 

;2键技能选择,同时3键是另一个技能
G2Skill := "dd-punch"

;a键技能选择
GaSkill := "punch+dd-weapon"

;q键空中连击类型选择
GqSkill := "simple" ;simple是一键连击,cancelable是按住键连击,松开键中止

} ;不缩进块

/* 游戏操作函数
*/ { ;不缩进块
  
;缩短MyKey的press函数名
press(key, pressDuration := 100){
  global MyKey
  return MyKey.press.Call(key, pressDuration)
}

;缩短MyKey的waitKeyUp函数名
waitKeyUp(key, waitTime, waitDuration := 60){
  global MyKey
  return MyKey.waitKeyUp.Call(key, waitTime, waitDuration)
}

;缩短MyKey的pressKeys函数名
pressKeys(keys, delays, duration := 50){
  global MyKey
  return MyKey.pressKeys.Call(keys, delays, duration)
}

;根据在Gui中输入的数据,制作全局变量数据
makeData(){
  global CT
  global GV
  global GweaponDelays
  global GjumpAtParams
  
  ;制作武器延时数组,因为直接使用必须计算出上次松开键到下次按键的时间
  GV.weaponDelayArr := StrSplit(GweaponDelays, ",")
  for k, v in GV.weaponDelayArr {
    GV.weaponDelayArr[k] := v-CT.weaponDuration
  }
  
  ;制作空中连击需要的数据
  tempArr := StrSplit(GjumpAtParams, ";")
  GV.jumpAtType := tempArr[1]
  atType := GV.jumpAtType
  GV.jumpAtDelayArr := StrSplit(tempArr[2], ",")
  for k, v in GV.jumpAtDelayArr {
    if (atType) 
      GV.jumpAtDelayArr[k] := v-CT.weaponDuration
    else
      GV.jumpAtDelayArr[k] := v-CT.punchDuration
    atType := !atType
  }
  
  ;显示最后制作时间,只显示时分不显示日期
  FormatTime, curTime
  SB_SetText("Last Submit = "+StrSplit(curTime, " ")[1])
  return
}

;武器连击,用wKey执行,放开wKey时中断
weaponAttacks(wKey){
  global CT
  global GV
  global GweaponDelays
  press(CT.weaponKey, CT.weaponDuration) ;必须持续按长时间,太短会无法反应!因为武器出手时间长
  for k, v in GV.weaponDelayArr {
    isKeyUp := waitKeyUp(wKey, v)
    if (isKeyUp) {
      OutputDebug, weapon key up
      return
    } else {
      OutputDebug, delayed %v% and press next weaponKey
      press(CT.weaponKey, CT.weaponDuration)
    }
  }
  OutputDebug, weapon attacks finished
  sleep, 100 ;防止按住键引发的下一次连击过早发生
  return
}

;空中连击,sKey表示出招按键,sType为类型,simple是一键连击,cancelable是松开键中止但必须按住键才能连击
jumpAttacks(sKey, sType){
  global CT
  global GV
  atType := GV.jumpAtType ;攻击类型
  for k, v in GV.jumpAtDelayArr {
    if (atType) 
      press(CT.weaponKey, CT.weaponDuration)
    else 
      press(CT.punchKey, CT.punchDuration)
    if (sType = "simple") {
      sleep, %v%
    } else {
      isKeyUp := waitKeyUp(sKey, v)
      if (isKeyUp) {
        return
      }
    }
    atType := !atType
  }
  if (atType) 
    press(CT.weaponKey, CT.weaponDuration)
  else 
    press(CT.punchKey, CT.punchDuration)
  return
}

;↓↑ab,大招,也可以用作影连和金刚的投技
duSkill(){
  global CTmacro12
  press("down", 50)
  sleep, 50
  send {up down}
  sleep, 50
  send {%CTmacro12% down}
  sleep, 50
  send {up up}
  send {%CTmacro12% up}
  return
}

;下下技能,参数表示是拳技能还是武器技能,"punch"是拳,否则就是武器
ddSkill(sType){
  global CT
  global CTpunchKey
  global CTweaponKey
  if (sType == "punch") {
    press("down", 50)
    sleep, 50
    pressKeys(["down", CTpunchKey], [30], CT.punchDuration)
  }else{
    press("down", 50)
    sleep, 50
    pressKeys(["down", CTweaponKey], [30], CT.weaponDuration)
  }
  return
}

} ;不缩进块

/* 加入Gui的函数
*/ { ;不缩进块
;平台选择
selectionUI(){
  global
  Gui, New, , 选择游戏平台
  Gui, add, ListBox, vGtitle, WinKawaks.exe|X-Zone.exe
  GuiControl, Choose, Gtitle, 1 
  Gui, add, Button, gButtonTitleSelect, 选择游戏平台
  Gui, show
}  

;主UI界面设置
setupUI(title){
  global
  Gui, New
  Gui, Add, Tab3,w230, params|skill select|hotkeys ;顺便测试标签页分组,下面直接加入的组件属于当前标签页
  Gui, Tab, params ;参数设定标签页的组件
  Gui, Add, Text, , weapon Attack Delays:
  Gui, Add, Edit, vGweaponDelays, %GweaponDelays% ;武器连击延时数组
  Gui, Add, Text, , jump Attack Params:
  Gui, Add, Edit, vGjumpAtParams, %GjumpAtParams% ;空中连击延时数组
  Gui, Tab, skill select ;技能选择标签页的组件
  Gui, Add, Text, , 2-key skill:
  Gui, Add, ComboBox, vG2Skill, dd-punch|dd-weapon ;2键技能选择
  GuiControl, Choose, G2Skill, 1 ;对ComboBox,可指定其初始选择
  Gui, Add, Text, , a-key skill:
  Gui, Add, ComboBox, vGaSkill, punch+dd-weapon|punch+dd-punch ;a键技能选择
  GuiControl, Choose, GaSkill, 1
  Gui, Add, Text, , q-key skill:
  Gui, Add, ComboBox, vGqSkill, simple|cancelable ;q键技能类型,一键连击或可松手中止
  GuiControl, Choose, GqSkill, 1
  Gui, Tab, hotkeys ;热键信息标签页
  Gui, Add, Text, , s - weapon attacks
  Gui, Add, Text, , q - jump attacks
  Gui, Add, Text, , a - punch+dd-selection
  Gui, Add, Text, , 2 and 3 - dd-selection
  Gui, Add, Text, , numpad0,numpad1,Rctrl - pause|start
  Gui, Tab ;标签页结束
  Gui, Add, Button, , Submit_ ;提交
  Gui, Add, Button, , Exit ;结束app
  Gui, Add, StatusBar , , ;状态栏,显示最后提交时间
  Gui, +AlwaysOnTop
  Gui, Show,w250h270, %Gtitle% - sengoku3
  makeData()
}

} ;不缩进块

/* Gui响应函数
*/ { ;不缩进块
ButtonSubmit_(){
  global
  Gui, Submit,NoHide ; 保存用户输入后每个控件的数据,NoHide可以在提交数据后保持窗体显示
  makeData()
  MsgBox, You have submit your changes!
}

ButtonExit(){
  ExitApp
}
GuiClose(){
  ExitApp
}

ButtonTitleSelect(){
  global
  Gui, Submit, Hide
  Gui, Destroy
  setupUI(Gtitle)
  setupHotkeys(Gtitle)
}

} ;不缩进块

/* 快捷键响应函数
*/ { ;不缩进块
;连发拳,为防止死循环,有最大次数限制,放开键则停止:
KeyW(){
  global
  
  loop, 50 {
    press(CT.punchKey, CT.punchDuration)
    if (!GetKeyState("w")) {
      break
    }
    sleep, % CT.punchDelay
  }
  return
}

;剑连发,按照GweaponDelays的延时进行连击
KeyS(){
  global
  weaponAttacks("s")
  return
}

;空中连击
KeyQ(){
  global
  jumpAttacks("q", GqSkill)
  return
}

;大忍术或影连,金刚的投技忍术
KeyR(){
  global
  duSkill()
  return
}

;重踢后立即连下下忍术
KeyA() {
  global
  press(CT.punchKey, CT.punchDuration)
  sleep, 150
  if (GaSkill = "punch+dd-weapon") {
    ddSkill("weapon")
  } else {
    ddSkill("punch")
  }
}

;下下忍术,2和3的技能可选并且相反
Key2(){
  global
  if (G2Skill = "dd-weapon") {
    ddSkill("weapon")
  } else {
    ddSkill("punch")
  }
  return
}
Key3(){
  global
  if (G2Skill = "dd-weapon") {
    ddSkill("punch")
  } else {
    ddSkill("weapon")
  }
  return
}

;游聚平台的老板键
bossKey(){
  send {Alt down}{Q down}
  sleep, 100
  send {Alt up}{Q up}
}

;切换静音
muteToggle(){
  SoundSet, +1, , Mute
}

;Winkawaks暂停
winkawaksPause(){
  send {Enter down}
  sleep, 100
  send {Enter up}
}

} ;不缩进块

/* 根据平台定义快捷键的函数 
*/ { ;不缩进块
setupHotkeys(title){
  global
  
  local exeTitle := "ahk_exe " . title
  if (exeTitle == "ahk_exe WinKawaks.exe") { ;模拟器WinKawaks
    Hotkey, IfWinActive, %exeTitle%
    Hotkey, ~s, KeyS
    Hotkey, ~q, KeyQ
    HotKey, ~r, KeyR
    HotKey, ~2, Key2
    HotKey, ~3, Key3
    HotKey, ~a, KeyA
    HotKey, ~Numpad0, winkawaksPause
    HotKey, ~Numpad1, muteToggle
    Hotkey, IfWinActive
  } else if (exeTitle == "ahk_exe X-Zone.exe") { ;游聚平台
    Hotkey, IfWinActive, %exeTitle%
    Hotkey, ~s, KeyS
    Hotkey, ~q, KeyQ
    HotKey, ~r, KeyR
    HotKey, ~2, Key2
    HotKey, ~3, Key3
    HotKey, ~a, KeyA
    HotKey, ~Numpad0, bossKey
    HotKey, ~Numpad1, muteToggle
    HotKey, ~w, KeyW ;增加连发键
    Hotkey, IfWinActive
  }
}
} ;不缩进块

/* 主函数,这里是只显示选择平台的UI,之后交给选择后的函数去处理
*/ { ;不缩进块
main(){
  global
  
  selectionUI()
  
}

} ;不缩进块

/* 运行脚本 
*/
main()
return
